// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use log::{debug, error};
use log4rs;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use std::thread::{self, sleep};
use std::time::Duration;
use tauri::{Manager, State};

mod capturer;
mod cv;
mod fitness;
mod window;
use crate::fitness::options::Options;
use crate::fitness::Fitness;
use crate::window::Window;

struct CState {
  hug_active: Arc<Mutex<bool>>,
  hug_options: Arc<Mutex<Options>>,
  is_f_pressed: Arc<Mutex<bool>>,
}

#[tauri::command]
fn capture(file: &str) {
  use xcap::Monitor;
  let monitors = Monitor::all().unwrap();
  let monitor = monitors.iter().find(|v| v.is_primary());
  if monitor.is_none() {
    return;
  }
  let img = monitor.unwrap().capture_image().unwrap();
  img.save(file).unwrap();
}
#[tauri::command]
fn toggle_hug(state: State<CState>) -> bool {
  let _mutex = Arc::clone(&state.hug_active);
  let mut _running = _mutex.lock().unwrap();
  *_running = !*_running;
  debug!("切换状态 {}", if *_running { "开始" } else { "结束" });
  *_running
}
#[tauri::command]
fn update_hug_setting(state: State<CState>, opts: Options) -> bool {
  debug!("{:?}", opts);
  let mut _options = state.hug_options.lock().unwrap();
  *_options = opts;
  true
}
#[tauri::command]
fn mouse_left_click(x: f32, y: f32) -> bool {
  debug!("click {} {}", x, y);
  Window::mouse_click(x, y);
  true
}
#[tauri::command]
fn log_to_file(msg: String) {
  error!("web: {}", msg);
}
#[tauri::command]
fn set_position(args: [i32; 4]) -> Option<String> {
  Window::set_win_pos(args)
}
#[tauri::command]
fn get_position() -> Option<[i32; 4]> {
  Window::get_win_pos()
}
#[tauri::command]
fn press_f_shot(state: State<CState>) {
  let is_f = Arc::clone(&state.is_f_pressed);
  let _mutex = is_f.clone();
  let mut _active = _mutex.lock().unwrap();
  if *_active {
    *_active = false;
    debug!("shot f released");
    return;
  }
  *_active = true;
  Window::press_key_ex("space");
  sleep(Duration::from_millis(40));
  Window::release_key_ex("space");
  debug!("shot f pressed");
}
#[cfg(debug_assertions)]
#[tauri::command]
fn toggle_deltool(window: tauri::Window) {
  if window.is_devtools_open() {
    window.close_devtools();
  } else {
    window.open_devtools();
  }
}
#[cfg(not(debug_assertions))]
#[tauri::command]
fn toggle_deltool(_window: tauri::Window) {}

fn main() {
  log4rs::init_file("log4rs.yaml", Default::default()).unwrap();

  use tauri::{CustomMenuItem, SystemTray, SystemTrayEvent, SystemTrayMenu};
  let tray_menu = SystemTrayMenu::new()
    // .add_item(CustomMenuItem::new("setting-cross".to_string(), "准星设置"))
    // .add_item(CustomMenuItem::new("setting-hug".to_string(), "挂机设置"))
    .add_item(CustomMenuItem::new("show-main".to_string(), "显示主窗口"))
    .add_item(CustomMenuItem::new("quit".to_string(), "退出助手"));
  let system_tray = SystemTray::new().with_menu(tray_menu);
  tauri::Builder::default()
    .plugin(tauri_plugin_single_instance::init(|_app, _argv, _cwd| {}))
    .setup(|app| {
      let window = app.get_window("main").unwrap();

      #[cfg(debug_assertions)] // only include this code on debug builds
      {
        window.open_devtools();
      }
      window.set_skip_taskbar(true)?;
      window.set_always_on_top(true)?;
      window.set_title("ASCUM")?;

      // let res_path = app.path_resolver().resolve_resource("imgs").unwrap();
      // let assets_path = res_path
      //   .as_os_str()
      //   .to_str()
      //   .unwrap()
      //   .replace("\\\\?\\", "");
      let assets_path = String::from("./imgs");

      // debug!("{}", assets_path.clone());
      let hug_options = Arc::new(Mutex::new(Options::default()));
      let hug_state = Arc::new(Mutex::new(false));
      // let driver = auto::AutoDrive::new(assets_path);
      let _hug_opts_mutex_inner = Arc::clone(&hug_options);
      let _hug_state_mutex_inner = Arc::clone(&hug_state);
      let _fitness = Fitness::new(assets_path);

      let (tx, rx) = channel::<String>();
      thread::spawn(move || _fitness.start(_hug_opts_mutex_inner, _hug_state_mutex_inner, tx));

      let is_f_pressed = Arc::new(Mutex::new(false));
      let is_f_pressed_clone = Arc::clone(&is_f_pressed);
      let state = CState {
        hug_active: Arc::clone(&hug_state),
        hug_options: Arc::clone(&hug_options),
        is_f_pressed,
      };
      app.manage(state);

      let _handle = app.app_handle().clone();
      thread::spawn(move || loop {
        if let Ok(err) = rx.recv() {
          debug!("{:?}", err);
          let _ = _handle.emit_to("main_win", "message", err);
        }
      });

      thread::spawn(move || loop {
        let _mutex = is_f_pressed_clone.clone();
        let _active = _mutex.lock().unwrap();
        let _running = *_active;
        drop(_active);
        if !_running {
          sleep(Duration::from_millis(500));
          continue;
        }
        Window::press_key_ex("f");
        sleep(Duration::from_millis(40));
        Window::release_key_ex("f");
        sleep(Duration::from_millis(200));
      });

      Ok(())
    })
    .system_tray(system_tray)
    .on_system_tray_event(move |app, event| match event {
      SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
        "quit" => {
          std::process::exit(0);
        }
        "setting-cross" => {
          app
            .emit_to("main", "setting-cross", ())
            .expect("can not emit to main window");
        }
        "setting-hug" => {
          app
            .emit_to("main", "setting-hug", ())
            .expect("can not emit to main window");
        }
        "clear-message" => {
          app
            .emit_to("main", "clear-message", ())
            .expect("can not emit to main window");
        }
        "show-main" => {
          app
            .emit_to("main", "show-main", ())
            .expect("can not emit to main window");
        }
        _ => {}
      },
      _ => {}
    })
    .invoke_handler(tauri::generate_handler![
      capture,
      toggle_deltool,
      toggle_hug,
      update_hug_setting,
      mouse_left_click,
      log_to_file,
      set_position,
      get_position,
      press_f_shot
    ])
    .run(tauri::generate_context!())
    .expect("error while running tauri application");
}
